#include "audiodecodethread.h"
#include "videoplayer.h"

#define CONFIG_AVFILTER 0

static void decoder_init(Decoder *d, AVCodecContext *avctx, PacketQueue *queue, SDL_cond *empty_queue_cond) {
    memset(d, 0, sizeof(Decoder));
    d->avctx = avctx;
    d->queue = queue;
    d->empty_queue_cond = empty_queue_cond;
    d->start_pts = AV_NOPTS_VALUE;
    d->pkt_serial = -1;
}

static void decoder_destroy2(Decoder *d) {
    av_packet_unref(&d->pkt);
}

static void decoder_abort2(Decoder *d, FrameQueue *fq)
{
  //  packet_queue_abort(d->queue);
    frame_queue_signal(fq);
    //SDL_WaitThread(d->decoder_tid, NULL);
    //d->decoder_tid = NULL;
   // packet_queue_flush(d->queue);
}


AudioDecodeThread::AudioDecodeThread(VideoPlayer *player):QThread(player)
{
    m_player=player;
}

void AudioDecodeThread::play()
{
    if(!this->isRunning()){
        m_reqPause=false;
        m_reqStop=false;
        this->start();
    }else{
        m_reqPause=false;
        m_reqStop=false;
        m_waitCond.wakeAll();
    }
}

void AudioDecodeThread::pause()
{
    m_reqPause=true;
    m_reqStop=false;
}

void AudioDecodeThread::stop()
{
    m_reqPause=false;
    m_reqStop=true;
    m_waitCond.wakeAll();
    this->wait();
}

void AudioDecodeThread::run()
{    
    PlayerInfo *is = (PlayerInfo *)m_player->m_playerInfo;

    if(!openDecoder()){
        emit error(m_lastErrorMsg);
        return;
    }

    emit inited();


    AVFrame *frame = av_frame_alloc();
    Frame *af;
#if CONFIG_AVFILTER
    int last_serial = -1;
    int64_t dec_channel_layout;
    int reconfigure;
#endif
    int got_frame = 0;
    AVRational tb;
    int ret = 0;

    if (!frame)
        return;

    bool frameValid;
    for(;;)
    {
        if(m_reqStop){
            goto the_end;
        }

        //解码
        if(!decodeNextFrame(frame,&frameValid)){
            emit error(m_lastErrorMsg);
            closeDecoder();
            return;
        }
        if(!frameValid){
             continue;
        }

        if (frameValid) {
            //tb = (AVRational){1, frame->sample_rate};
            tb.num=1;
            tb.den=frame->sample_rate;

#if CONFIG_AVFILTER
            dec_channel_layout = get_valid_channel_layout(frame->channel_layout, frame->channels);

            reconfigure =
                    cmp_audio_fmts(is->audio_filter_src.fmt, is->audio_filter_src.channels,
                                   (AVSampleFormat)frame->format, frame->channels)    ||
                    is->audio_filter_src.channel_layout != dec_channel_layout ||
                    is->audio_filter_src.freq           != frame->sample_rate ||
                    is->auddec.pkt_serial               != last_serial;

            if (reconfigure) {
                char buf1[1024], buf2[1024];
                av_get_channel_layout_string(buf1, sizeof(buf1), -1, is->audio_filter_src.channel_layout);
                av_get_channel_layout_string(buf2, sizeof(buf2), -1, dec_channel_layout);
                av_log(NULL, AV_LOG_DEBUG,
                       "Audio frame changed from rate:%d ch:%d fmt:%s layout:%s serial:%d to rate:%d ch:%d fmt:%s layout:%s serial:%d\n",
                       is->audio_filter_src.freq, is->audio_filter_src.channels, av_get_sample_fmt_name((AVSampleFormat)is->audio_filter_src.fmt), buf1, last_serial,
                       frame->sample_rate, frame->channels, av_get_sample_fmt_name((AVSampleFormat)frame->format), buf2, is->auddec.pkt_serial);

                is->audio_filter_src.fmt            = (AVSampleFormat)frame->format;
                is->audio_filter_src.channels       = frame->channels;
                is->audio_filter_src.channel_layout = dec_channel_layout;
                is->audio_filter_src.freq           = frame->sample_rate;
                last_serial                         = is->auddec.pkt_serial;

                if ((ret = configure_audio_filters(is, afilters, 1)) < 0)
                    goto the_end;
            }

            if ((ret = av_buffersrc_add_frame(is->in_audio_filter, frame)) < 0)
                goto the_end;

            while ((ret = av_buffersink_get_frame_flags(is->out_audio_filter, frame, 0)) >= 0) {
                tb = av_buffersink_get_time_base(is->out_audio_filter);
#endif
                if (!(af = frame_queue_peek_writable(&is->audioFrameQueue)))
                    goto the_end;

                af->pts = (frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * av_q2d(tb);
                af->pos = frame->pkt_pos;
                af->serial = is->auddec.pkt_serial;
                af->duration = av_q2d((AVRational){frame->nb_samples, frame->sample_rate});

                av_frame_move_ref(af->frame, frame);
                frame_queue_push(&is->audioFrameQueue);

#if CONFIG_AVFILTER
                if (is->audioq.serial != is->auddec.pkt_serial)
                    break;
            }
            if (ret == AVERROR_EOF)
                is->auddec.finished = is->auddec.pkt_serial;
#endif
        }
        if(m_reqStop){
            break;
        }
        if(ret<0){
            if(ret != AVERROR(EAGAIN) && ret != AVERROR_EOF){
                break;
            }
        }
    };
the_end:
#if CONFIG_AVFILTER
    avfilter_graph_free(&is->agraph);
#endif
    av_frame_free(&frame);
    closeDecoder();
}


bool AudioDecodeThread::openDecoder()
{
    PlayerInfo *is = m_player->m_playerInfo;
    AVCodecContext* codecContext=NULL;
    AVCodec* codec=NULL;
    AVFormatContext *ic = is->formatContext;

    AVDictionaryEntry *t = NULL;
    int sample_rate, nb_channels;
    int64_t channel_layout;
    int ret = 0;
    int stream_lowres = 0;  //低分辨率等级
    int fast=0;

    //初始化解码器上下文
    codecContext = avcodec_alloc_context3(NULL);
    if (!codecContext){
        m_lastErrorMsg="avcodec_alloc_context3失败";
        return false;
    }
    ret = avcodec_parameters_to_context(codecContext, m_player->m_playerInfo->audioStream->codecpar);
    if (ret < 0){
        closeDecoder();
        m_lastErrorMsg=QString("解码器上下文初始化失败（%1）").arg(avErrorCodeToString(ret));
        return false;
    }

    //查找解码器 TODO: 解码器可配置
    QString forceCodecName;
    if(forceCodecName!=""){
        codec=avcodec_find_decoder_by_name(forceCodecName.toStdString().data());
    }
    if(!codec){
        codec = avcodec_find_decoder(codecContext->codec_id);
    }
    if(!codec){
        closeDecoder();
        m_lastErrorMsg="未找到合适的解码器";
        return false;
    }

    //设置解码器参数 TODO：解码器参数可配置
    codecContext->codec_id = codec->id;

    av_codec_set_pkt_timebase(codecContext, m_player->m_playerInfo->audioStream->time_base);

    if(stream_lowres > av_codec_get_max_lowres(codec)){
        av_log(codecContext, AV_LOG_WARNING, "The maximum value for lowres supported by the decoder is %d\n",
               av_codec_get_max_lowres(codec));
        stream_lowres = av_codec_get_max_lowres(codec);
    }
    av_codec_set_lowres(codecContext, stream_lowres);

#if FF_API_EMU_EDGE
    if(stream_lowres) codecContext->flags |= CODEC_FLAG_EMU_EDGE;
#endif
    if (fast)
        codecContext->flags2 |= AV_CODEC_FLAG2_FAST;
#if FF_API_EMU_EDGE
    if(codec->capabilities & AV_CODEC_CAP_DR1)
        codecContext->flags |= CODEC_FLAG_EMU_EDGE;
#endif


    //打开解码器 TODO：解码器参数可配置
    AVDictionary *opts=NULL;
//    AVDictionary *opts = filter_codec_opts(codec_opts, codecContext->codec_id, ic, ic->streams[stream_index], codec);
//    if (!av_dict_get(opts, "threads", NULL, 0))
//        av_dict_set(&opts, "threads", "auto", 0);
//    if (stream_lowres)
//        av_dict_set_int(&opts, "lowres", stream_lowres, 0);
//    if (codecContext->codec_type == AVMEDIA_TYPE_VIDEO || codecContext->codec_type == AVMEDIA_TYPE_AUDIO)
//        av_dict_set(&opts, "refcounted_frames", "1", 0);

    if ((ret = avcodec_open2(codecContext, codec, &opts)) < 0) {
        closeDecoder();
        m_lastErrorMsg=QString("解码器打开失败（%1）").arg(avErrorCodeToString(ret));
        return false;
    }

    m_player->m_playerInfo->audioCodecContext=codecContext;
    m_player->m_playerInfo->audioCodec=codec;
    if (( m_player->m_playerInfo->formatContext->iformat->flags & (AVFMT_NOBINSEARCH | AVFMT_NOGENSEARCH | AVFMT_NO_BYTE_SEEK)) && ! m_player->m_playerInfo->formatContext->iformat->read_seek) {
         m_player->m_playerInfo->auddec.start_pts =  m_player->m_playerInfo->audioStream->start_time;
         m_player->m_playerInfo->auddec.start_pts_tb =  m_player->m_playerInfo->audioStream->time_base;
    }

    decoder_init(&is->auddec, codecContext, &is->audioPacketQueue, is->continue_read_thread);

    return true;
}

void AudioDecodeThread::closeDecoder()
{
    PlayerInfo* playerInfo=m_player->m_playerInfo;

    decoder_abort2(&playerInfo->viddec, &playerInfo->videoFrameQueue);
    decoder_destroy2(&playerInfo->viddec);

    swr_free(&playerInfo->swr_ctx);
    av_freep(&playerInfo->audio_buf1);
    playerInfo->audio_buf1_size = 0;
    playerInfo->audio_buf = NULL;

    if (playerInfo->rdft) {
        av_rdft_end(playerInfo->rdft);
        av_freep(&playerInfo->rdft_data);
        playerInfo->rdft = NULL;
        playerInfo->rdft_bits = 0;
    }

    if(m_player->m_playerInfo->audioCodecContext){
        avcodec_free_context(&m_player->m_playerInfo->audioCodecContext);
        m_player->m_playerInfo->audioCodecContext=NULL;
    }
    m_player->m_playerInfo->audioCodec=NULL;
}

bool AudioDecodeThread::decodeNextFrame( AVFrame *frame,bool* valid)
{
    PlayerInfo* is = m_player->m_playerInfo;
    Decoder *d = &is->auddec;
    int decoder_reorder_pts=-1;  //是否需要让解码器重新排布pts
    int framedrop=-1;            //是否丢包

    int ret = AVERROR(EAGAIN);

    *valid=false;
    for (;;) {
        if(m_reqStop){
            return true;
        }

        AVPacket pkt;

        if (d->queue->serial == d->pkt_serial) {
            do {
                if (d->queue->abort_request || m_reqStop)
                    return true;

                //读取解码后的帧
                ret = avcodec_receive_frame(d->avctx, frame);

                //计算PTS
                if (ret >= 0) {
                    AVRational tb = (AVRational){1, frame->sample_rate};
                    if (frame->pts != AV_NOPTS_VALUE)
                        frame->pts = av_rescale_q(frame->pts, av_codec_get_pkt_timebase(d->avctx), tb);
                    else if (d->next_pts != AV_NOPTS_VALUE)
                        frame->pts = av_rescale_q(d->next_pts, d->next_pts_tb, tb);
                    if (frame->pts != AV_NOPTS_VALUE) {
                        d->next_pts = frame->pts + frame->nb_samples;
                        d->next_pts_tb = tb;
                    }
                }



                //到达流尾时重置解码器
                if (ret == AVERROR_EOF) {
                    d->finished = d->pkt_serial;
                    avcodec_flush_buffers(d->avctx);
                    return false;
                }

                if (ret >= 0){
                    *valid=true;
                    return true;
                }
            } while (ret != AVERROR(EAGAIN));
        }

        //从包缓存中取出一包
        do {
            if(m_reqStop){
                return true;
            }
            if (d->queue->nb_packets == 0){
                SDL_CondSignal(d->empty_queue_cond);
            }
            if (d->packet_pending) {
                av_packet_move_ref(&pkt, &d->pkt);
                d->packet_pending = 0;
            } else {
                if (packet_queue_get(d->queue, &pkt, 1, &d->pkt_serial) < 0)
                    return true;
            }
        } while (d->queue->serial != d->pkt_serial);

        //对取出的包进行解码
        if (pkt.data == is->flushPkt.data) {
            avcodec_flush_buffers(d->avctx);
            d->finished = 0;
            d->next_pts = d->start_pts;
            d->next_pts_tb = d->start_pts_tb;
        } else {
            if (avcodec_send_packet(d->avctx, &pkt) == AVERROR(EAGAIN)) {
                av_log(d->avctx, AV_LOG_ERROR, "Receive_frame and send_packet both returned EAGAIN, which is an API violation.\n");
                d->packet_pending = 1;
                av_packet_move_ref(&d->pkt, &pkt);
            }
            av_packet_unref(&pkt);
        }
    }

    if (*valid) {
        frame->sample_aspect_ratio = av_guess_sample_aspect_ratio(is->formatContext, is->audioStream, frame);

        //执行音视频同步（对视频帧进行人工丢包）
//        double dpts = NAN;
//        if (frame->pts != AV_NOPTS_VALUE)
//            dpts = av_q2d(is->video_st->time_base) * frame->pts;
//        if (framedrop>0 || (framedrop && get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER)) {
//            if (frame->pts != AV_NOPTS_VALUE) {
//                double diff = dpts - get_master_clock(is);
//                if (!isnan(diff) && fabs(diff) < AV_NOSYNC_THRESHOLD &&
//                        diff - is->frame_last_filter_delay < 0 &&
//                        is->viddec.pkt_serial == is->vidclk.serial &&
//                        is->videoq.nb_packets) {
//                    is->frame_drops_early++;
//                    av_frame_unref(frame);
//                    ok = false;
//                }
//            }
//        }
    }

    return true;
}

bool AudioDecodeThread::enqueueFrame( AVFrame *src_frame, double pts, double duration, int64_t pos, int serial)
{
    Frame *vp;

#if defined(DEBUG_SYNC)
    printf("frame_type=%c pts=%0.3f\n",
           av_get_picture_type_char(src_frame->pict_type), pts);
#endif

    if (!(vp = frame_queue_peek_writable(&m_player->m_playerInfo->audioFrameQueue)))
        return true;

    vp->sar = src_frame->sample_aspect_ratio;
    vp->width = src_frame->width;
    vp->height = src_frame->height;
    vp->format = src_frame->format;

    vp->pts = pts;
    vp->duration = duration;
    vp->pos = pos;
    vp->serial = serial;
    vp->uploaded = 0;

    //set_default_window_size(vp->width, vp->height, vp->sar);

    av_frame_move_ref(vp->frame, src_frame);
    frame_queue_push(&m_player->m_playerInfo->audioFrameQueue);
    return true;
}
